/*************************************
 * Created by WebStorm
 * Author : 菲尔敦
 * QQ邮箱：2891044172@qq.com  手机号：15981761402
 * Created Time :2024/2/5 17:41
 Desc :工具
 **************************************/
import {Config} from '@/config';
import {NIcon,TreeSelectOption} from 'naive-ui';
import type {Component} from 'vue'
import {h, nextTick,toRaw} from 'vue';
import {isObject,isUrl} from '@/util/is';
import icons from '@/libs/icons';
import {DotMark} from '@vicons/carbon';
import SparkMD5 from 'spark-md5';

const LOCAL_STORAGE_KEY = Config.LOCAL_STORAGE_key;
const Layout = () => import('@/layout/index.vue');
const IFrame = () => import('@/layout/components/IFrame');
/**
 * 本地保存数据
 * @param key
 * @param data
 */
export function setLocalStorage(key: string, data: any) {
    localStorage.setItem(LOCAL_STORAGE_KEY + key, JSON.stringify(data));
}

/**
 * 读取本都数据
 * @param key
 */
export function getLocalStorage(key: string): any {
    const list = localStorage.getItem(LOCAL_STORAGE_KEY + key);
     return list !== null || true || list!="undefined"? JSON.parse(<string>list) :false ;
}

export function removeLocalStorage(key: string) {
    localStorage.removeItem(LOCAL_STORAGE_KEY + key);
}

/**
 * 处理icon
 * @param icon 图标
 * @param sizeNum 图标大小
 */
export function renderIcon(icon: Component,sizeNum:number=0) {
    if (sizeNum){
        return () => h(NIcon, {size:sizeNum}, {default: () => h(icon)});
    }else {
        return () => h(NIcon, null, {default: () => h(icon)});
    }
}

/**
 * 根据通过的百分比点亮6字符十六进制颜色
 * @param {string} color color The color to change
 * @param {number} amount amount The amount to change the color by
 */
export function lighten(color: string, amount: number) {
    color = color.indexOf("#") >= 0 ? color.substring(1, color.length) : color;
    amount = Math.trunc((255 * amount) / 100);
    return `#${addLight(color.substring(0, 2), amount)}${addLight(
        color.substring(2, 4),
        amount
    )}${addLight(color.substring(4, 6), amount)}`;
}

function addLight(color: string, amount: number) {
    const cc = parseInt(color, 16) + amount;
    const c = cc > 255 ? 255 : cc;
    return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`;
}

/**
 * 获取简易的路由对象
 * @param route
 */
export function getSimpleRoute(route: any) {
    const {fullPath, hash, meta, name, params, path, query} = route;
    return {fullPath, hash, meta, name, params, path, query};
}

/**
 * 递归菜单数据格式
 * @param routerMap
 */
export function generatorMenu(routerMap: Array<any>): any[] {
    const res: Array<any> = [];
    routerMap.map(((item: {
        name: string;
        meta: { title: string; icon: { name: any; render: any }; hideInMenu: boolean; href: string | undefined };
        children: any[];
    }) => {
        if (!item.meta || (item.meta && !item.meta.hideInMenu)) {
            const isRoot = isRootRouter(item);
            const info = isRoot ? item.children[0] : item;
            const currentMenu: any = {
                label: info.meta?.title,
                key: info.name,
            };
            if (item.meta.href) {
                currentMenu.href = item.meta.href;
            }
            //处理图标
            if (info.meta.icon) {
                // @ts-ignore
                const icon = icons[info.meta.icon];
                currentMenu.icon = renderIcon(icon);
            } else {
                // @ts-ignore
                currentMenu.icon = isRoot ? renderIcon(icons[item.meta.icon]) : renderIcon(DotMark);
            }
            // 是否有子菜单，并递归处理
            if (info.children && info.children.length > 0) {
                // Recursion
                currentMenu.children = generatorMenu(info.children);
            }
            res.push(currentMenu);
        }
    }))
    return res;
}

let viewsModules: Record<string, () => Promise<Recordable>>;

/**
 * 处理后台传过来的菜单路由数据
 * @param menuMap
 */
export function generateRoutesByServer(menuMap: Array<any>): any[] {
    let res: Array<any> = []
    viewsModules = viewsModules || import.meta.glob('/src/view/**/*');
    menuMap.map((item: {
        name: string;
        path: string;
        component: string;
        meta: { title: string; icon: string | number; hideInMenu: boolean; href: string | null; };
        children: any[];
    }) => {
        let component: (() => Promise<Recordable<any>>) | undefined;
        const hideMenu: boolean = item.meta.hideInMenu;
        if (item.component == 'Layout') {
            component = Layout;
        } else if (item.component == 'IFrame') {
            component = IFrame;
        } else {
            component = dynamicImport(viewsModules, item.component);
        }
        const currentRouter: any = {
            name: item.name,
            path: item.path,
            meta: {title: item.meta?.title, hideInMenu: hideMenu, icon: item.meta.icon, href: item.meta.href},
            component: component
        };
        // 是否有子菜单，并递归处理
        if (item.children && item.children.length > 0) {
            currentRouter.children = generateRoutesByServer(item.children);
        }
        res.push(currentRouter)
    })
    return res;
}

/**
 * 动态导入页面
 * */
export const dynamicImport = (
    viewsModules: Record<string, () => Promise<Recordable>>,
    component: string
) => {
    const keys = Object.keys(viewsModules);
    const matchKeys = keys.filter((key) => {
        let k = key.replace('/src/view', '');
        return k === component + "/index.ts" || k === component;
    });
    if (matchKeys?.length === 1) {
        const matchKey = matchKeys[0];
        return viewsModules[matchKey];
    }
    if (matchKeys?.length > 1) {
        console.warn(
            '请不要创建“.vue”和“.ts”视图文件夹下相同层次目录中具有相同文件名的文件。这将导致动态引入失败'
        );
        return;
    }
};

/**
 * 判断根路由 Router
 * */
export function isRootRouter(item: {
    meta: {
        hideInMenu: any;
        icon: { name: any; render: any };
    };
    children: any[];
}) {
    return item.children?.length === 1;
}

/**
 * 返回树形结构的父级
 * @param treeData 树形结构数据
 * @param key 要查找父级的子元素
 */
export function findMenuParent(treeData: any, key: string | number | symbol | undefined): string[] | any[] | undefined {
    if (treeData.length === 0) return [];
    for (let i = 0; i < treeData.length; i++) {
        if (treeData[i].key === key) {
            return [];
        } else {
            if (treeData[i].children) {
                const res: string[] | any[] | undefined = findMenuParent(treeData[i].children, key);
                if (res !== undefined) {
                    return res.concat(treeData[i].key);
                }
            }
        }
    }
}
/**
 * 将对象添加当作参数拼接到URL上面
 * @param baseUrl 需要拼接的url
 * @param obj 参数对象
 * @returns {string} 拼接后的对象
 * 例子:
 *  let obj = {a: '3', b: '4'}
 *  setObjToUrlParams('www.baidu.com', obj)
 *  ==>www.baidu.com?a=3&b=4
 */
export function setObjToUrlParams(baseUrl: string, obj: object): string {
    let parameters = '';
    let url;
    for (const key in obj) {
        // @ts-ignore
        parameters += key + '=' + encodeURIComponent(obj[key]) + '&';
    }
    parameters = parameters.replace(/&$/, '');
    if (/\?$/.test(baseUrl)) {
        url = baseUrl + parameters;
    } else {
        url = baseUrl.replace(/\/?$/, '?') + parameters;
    }
    return url;
}
export function deepMerge<T = any>(src: any = {}, target: any = {}): T {
    let key: string;
    for (key in target) {
        src[key] = isObject(src[key]) ? deepMerge(src[key], target[key]) : (src[key] = target[key]);
    }
    return src;
}
/**
 * 树形结构数据转换成一维数组
 * @param treeData 树形结构数据
 * @param result 返回结果
 */
export function flattenTreeData(treeData: any, result: any = []) {
    for (let i = 0; i < treeData.length; i++) {
        result.push(toRaw(treeData[i]));
        if (treeData[i].children && treeData[i].children.length > 0) {
            flattenTreeData(treeData[i].children, result);
        }
    }
    return result;
}

/**
 * 数组a的元素是否在数组b中存在
 * @param a 数组a
 * @param b 数组b
 */
export function isSubset<T>(a: T[], b: T[]): boolean {
    return a.some(val => b.includes(val));
}

/**
 * 指定权限是否存在
 * @param value
 */
export function permsJudg(value: string): boolean {
    const authorities = getLocalStorage('authorities');
    return authorities.some((item: { authority: string; }) => item.authority === value);
}

export function difference<T>(array1: T[], array2: T[]): T[] {
    return array1.filter(item => !array2.includes(item));
}

/**
 * 找出两个数组中重复出现的对象，并且只保留一个
 * @param array1
 * @param array2
 */
export function uniqueValues<T>(array1: T[], array2: T[]): T[] {
    const combined = [...array1, ...array2];
    const uniqueStringSet = new Set(combined.map(item => JSON.stringify(item)));
    return Array.from(uniqueStringSet).map(item => JSON.parse(item));
}

/**
 * 数组对象中存在就删除，不存在则添加到数组对象中
 * @param array 数组
 * @param object 对象
 */
export function updateArray<T>(array: T[], object: T): T[] {
    const index = array.findIndex(item => JSON.stringify(item) === JSON.stringify(object));
    if (index !== -1) {
        // 对象存在，删除它
        array.splice(index, 1);
    } else {
        // 对象不存在，添加它
        array.push(object);
    }
    return array;
}

/**
 * 数组对象中删除指定对象
 * @param array 数组对象
 * @param object 对象
 */
export function removeObject<T>(array: T[], object: T): T[] {
    return array.filter(item => JSON.stringify(item) !== JSON.stringify(object));
}

/**
 * 给指定元素添加样式clas
 * @param el 指定元素
 * @param className 新增的样式class
 */
export function addClass(el: any, className: string) {
    if (!el.classList.contains(className)) {
        el.classList.add(className)
    }
}

/**
 * 从指定元素中删除指定样式class
 * @param el
 * @param className
 */
export function removeClass(el: any, className: string) {
    el.classList.remove(className)
}

/**
 * 给指定元素添加错误提示框颜色/从指定元素除去错误提示框颜色
 * @param el 指定元素
 * @param status 状态  true:除去错误提示框样式class  false:添加错误提示框样式class
 */
export async function errBorderColor(el: any, status: boolean = false) {
    await nextTick();
    if (status) {
        if (el){
            removeClass(el, 'error-border');
        }
    } else {
        addClass(el, 'error-border');
    }
}

/**
 * 根据请求Header里的contentType转换参数
 * @param contentType
 * @param requestData
 */
export function transformRequestData(contentType:string, requestData:object) {
    requestData = requestData || {};
    if (contentType.includes('application/x-www-form-urlencoded')){
        let str='';
        for (const key in requestData){
            if (Object.prototype.hasOwnProperty.call(requestData,key)){
                str+=`${key}=${requestData[key]}&`;
            }
        }
        return encodeURI(str.slice(0,str.length-1));
    }else if ('multipart/form-data'){
        const formData=new FormData();
        for (const  key in  requestData){
            const files=requestData[key];
            //判断是否文件流
            const isFile=files?files.constructor===FileList||(files.constructor=== Array && files[0].constructor===File):false;
            if (isFile){
                for (let i=0;i<files.length;i++){
                    formData.append(key,files[i]);
                }
            }else {
                formData.append(key,files)
            }
        }
        return formData;
    }
    //json 字符串key
    return Object.keys(requestData).length?JSON.stringify(requestData):'';
}
export function downloadEvt(blobs: any, filename: "" | string | undefined) {
    let link = document.createElement('a');
    if (typeof filename === "string") {
        link.download = filename;
    }
    link.href = URL.createObjectURL(blobs);
    link.style.display = 'none';
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    window.URL.revokeObjectURL(blobs);
}

/**
 * TreeSelect中传子级的key获取父级数据
 * @param data
 * @param key
 */
export function findParentByKey(data: TreeSelectOption[], key: number|null): TreeSelectOption | null {
    let parent: TreeSelectOption | null = null;

    function search(data: TreeSelectOption[], key: number|null, parentCandidate: TreeSelectOption | null = null): boolean {
        for (const node of data) {
            if (node.key === key) {
                parent = parentCandidate;
                return true;
            }
            if (node.children) {
                const found = search(node.children, key, node);
                if (found) return true;
            }
        }
        return false;
    }
    search(data, key);
    return parent;
}
export function getFileMd5(file: File): Promise<string> {
    return new Promise((resolve, reject) => {
        let fileReader = new FileReader();
        fileReader.onload = function (event) {
            if (event.target && event.target.result instanceof ArrayBuffer) {
                let fileMd5 = SparkMD5.ArrayBuffer.hash(event.target.result);
                resolve(fileMd5);
            } else {
                reject(new Error('Failed to read file as ArrayBuffer'));
            }
        };
        fileReader.readAsArrayBuffer(file);
    });
}

/**
 * 获取文件扩展名
 * @param fileName
 */
export  function getExtension  (fileName: string): string {
    return fileName.slice((Math.max(0, fileName.lastIndexOf(".")) || Infinity) + 1);
}

/**
 * 从身份证号码中取出出生日和性别
 * @param idCard 身份证号码
 */
export function extractInfoFromIDCard(idCard: string): { birthday: string, gender: string } {
    const birthday = idCard.substring(6, 14); // 从身份证号码中提取出生日部分
    const year = birthday.substring(0, 4);
    const month = birthday.substring(4, 6);
    const day = birthday.substring(6, 8);
    const formattedBirthday = `${year}-${month}-${day}`;

    const genderCode = parseInt(idCard.charAt(16), 10); // 获取身份证号码中的性别码
    const gender = genderCode % 2 === 0 ? '女' : '男';

    return { birthday: formattedBirthday, gender };
}

/**
 * 处理图片链接
 * @param img_src
 */
export const imagePreview =  (img_src: string)=> {
    return isUrl(img_src) ? img_src : Config.VIEW_FILE + img_src;
}


export function updateStringArray(array: string[], str: string): string[] {
    const index = array.indexOf(str);
    if (index !== -1) {
        // 字符串存在，删除它
        array.splice(index, 1);
    } else {
        // 字符串不存在，添加它
        array.push(str);
    }
    return array;
}